<html>
 <head>
  <meta charset="UTF-8">
 </head>
 <body>
  <h1 data-lake-id="dnVpi" id="dnVpi"><span data-lake-id="u902cbac6" id="u902cbac6">典型回答</span></h1>
  <p data-lake-id="ue2b1daaa" id="ue2b1daaa"><br></p>
  <p data-lake-id="u063b5921" id="u063b5921"><span data-lake-id="u71436b08" id="u71436b08">一次完整的GC流程大致如下，基于JDK 1.8：</span></p>
  <p data-lake-id="uda91ce68" id="uda91ce68"><span data-lake-id="uf713686c" id="uf713686c">​</span><br></p>
  <p data-lake-id="u725ed5c4" id="u725ed5c4"><img src="https://cdn.nlark.com/yuque/0/2023/png/5378072/1686386059924-4108d531-5e5f-4911-b4d9-cbb044835594.png?x-oss-process=image%2Fwatermark%2Ctype_d3F5LW1pY3JvaGVp%2Csize_39%2Ctext_SmF2YSA4IEd1IFA%3D%2Ccolor_FFFFFF%2Cshadow_50%2Ct_80%2Cg_se%2Cx_10%2Cy_10"></p>
  <p data-lake-id="u79aa9974" id="u79aa9974"><br></p>
  <p data-lake-id="u075bbe53" id="u075bbe53"><span data-lake-id="uf82180a6" id="uf82180a6">一般来说，GC的触发是在对象分配过程中，当一个对象在创建时，他会根据他的大小决定是进入年轻代或者老年代。如果他的大小超过</span><code data-lake-id="ue256c87a" id="ue256c87a"><span data-lake-id="u3f4b348e" id="u3f4b348e">-XX:PretenureSizeThreshold</span></code><span data-lake-id="u5290a6fb" id="u5290a6fb">就会被认为是大对象，直接进入老年代，否则就会在年轻代进行创建。（PretenureSizeThreshold默认是0，也就是说，默认情况下对象不会提前进入老年代，而是直接在新生代分配。然后就GC次数和基于动态年龄判断来进入老年代。）</span></p>
  <p data-lake-id="u2c0fad09" id="u2c0fad09"><span data-lake-id="uddd5ab64" id="uddd5ab64">​</span><br></p>
  <p data-lake-id="ud144949e" id="ud144949e"><span data-lake-id="u8ebe422a" id="u8ebe422a">在年轻代创建对象，会发生在Eden区，但是这个时候有可能会因为Eden区内存不够，这时候就会尝试触发一次YoungGC。</span></p>
  <p data-lake-id="ub8fb2a6e" id="ub8fb2a6e"><span data-lake-id="u0deddb64" id="u0deddb64">​</span><br></p>
  <p data-lake-id="udeae679d" id="udeae679d"><span data-lake-id="u40be71fe" id="u40be71fe">年轻代采用的是标记复制算法，主要分为，标记、复制、清除三个步骤，会从GC Root开始进行存活对象的标记，然后把Eden区和Survivor区复制到另外一个Survivor区。然后再把Eden和From Survivor区的对象清理掉。</span></p>
  <p data-lake-id="u522e6703" id="u522e6703"><span data-lake-id="u8535b979" id="u8535b979">​</span><br></p>
  <p data-lake-id="u78283ecf" id="u78283ecf"><span data-lake-id="u0948d2ca" id="u0948d2ca">这个过程，可能会发生两件事情，第一个就是Survivor有可能存不下这些存活的对象，这时候就会进行空间分配担保。如果担保成功了，那么就没什么事儿，正常进行Young GC就行了。但是如果担保失败了，说明老年代可能也不够了，这时候就会触发一次FullGC了。</span></p>
  <p data-lake-id="uec2db7f2" id="uec2db7f2"><span data-lake-id="u4e7ee364" id="u4e7ee364">​</span><br></p>
  <p data-lake-id="uccbd11ee" id="uccbd11ee"><span data-lake-id="ucf911ebc" id="ucf911ebc">还会发生第二件事情就是，在这个过程中，会进行对象的年龄判断，如果他经过一定次数的GC之后，还没有被回收，那么这个对象就会被放到老年代当中去。</span></p>
  <p data-lake-id="u4fa728f4" id="u4fa728f4"><span data-lake-id="u5b9bef62" id="u5b9bef62">​</span><br></p>
  <p data-lake-id="ub2eba236" id="ub2eba236"><span data-lake-id="ud088e46b" id="ud088e46b">而老年代如果不够了，或者担保失败了，那么就会触发老年代的GC，一般来说，现在用的比较多的老年代的垃圾收集器是CMS或者G1，他们采用的都是三色标记法。</span></p>
  <p data-lake-id="ud09077e8" id="ud09077e8"><span data-lake-id="ubb5489d2" id="ubb5489d2">​</span><br></p>
  <p data-lake-id="u32e9bf1b" id="u32e9bf1b"><span data-lake-id="u7ac8f791" id="u7ac8f791">也就是分为四个阶段：初始标记、并发标记、重新标记、及并发清理。</span></p>
  <p data-lake-id="uf5b4942d" id="uf5b4942d"><span data-lake-id="u44030170" id="u44030170">​</span><br></p>
  <p data-lake-id="u8b078561" id="u8b078561"><span data-lake-id="u8b53256b" id="u8b53256b">老年代在做FullGC之后，如果空间还是不够，那就要触发OOM了。</span></p>
  <p data-lake-id="u23d65014" id="u23d65014"><span data-lake-id="u04ef914a" id="u04ef914a">​</span><br></p>
  <p data-lake-id="ueb331225" id="ueb331225"><span data-lake-id="ub5008c2c" id="ub5008c2c">​</span><br></p>
  <p data-lake-id="uda534c88" id="uda534c88"><span data-lake-id="ud0539f99" id="ud0539f99">​</span><br></p>
  <p data-lake-id="uc9c74393" id="uc9c74393"><br></p>
 </body>
</html>